import _ from "lodash";
import { GameRoomEntity, IGameRoom } from "../logic/room/GameRoomEntity";
import { UserEntity } from "./UserEntity";
import { LogicServer } from "../../LogicServer";
import { RoomConfig } from "../config/RoomConfig";
import { EnumCacheGroup } from "../../../../common/enum/EnumCacheGroup";
import { EnumErrorCode } from "../../../../common/enum/EnumErrorCode";
import { GameRoomInfo } from "../../../../common/model/GameRoomInfo";
import { EnumProtocolType } from "../../../../common/protocols/EnumProtocolType";
import { CS_Bet, SC_Bet } from "../../../../common/protocols/Proto_Bet";
import { CS_EnterGameRoom, SC_EnterGameRoom } from "../../../../common/protocols/Proto_EnterGameRoom";
import { CS_GetRoomInfo, SC_GetRoomInfo } from "../../../../common/protocols/Proto_GetRoomInfo";
import { SC_GetRoomList } from "../../../../common/protocols/Proto_GetRoomList";
import { CacheComponent } from "../../../../framework/service/Components/CacheComponent";
import { IMsg } from "../../../../framework/service/Components/WorkOrderInfo";
import { Tools } from "../../../../framework/utils/Tools";
import { SC_GetBetHistory } from "../../../../common/protocols/Proto_GetBetHistory";
import { GameBetOrderInfo } from "../../../../common/model/GameBetOrderInfo";
import { EnumRoomType } from "../../../../common/enum/EnumRoomType";
import { Log } from "../../../../framework/utils/Log";
import { GameRoomFastSingle } from "../logic/room/GameRoomFastSingle";
import { SC_ExitGameRoom } from "../../../../common/protocols/Proto_ExitGameRoom";


export class RoomManager {

    private static _instance: RoomManager;

    private _rooms: GameRoomEntity[] = [];

    public static get inst(): RoomManager {
        if (!this._instance) {
            this._instance = new RoomManager();

        }
        return this._instance;
    }

    public getRoom(roomid: string): IGameRoom {
        return _.find(this._rooms, { uid: roomid });
    }

    public async commingRequest(req: IMsg, user: UserEntity): Promise<void> {

        switch (req.cmdid) {
            case EnumProtocolType.CS_Bet: {
                const cs: CS_Bet = new CS_Bet();
                const sc: SC_Bet = new SC_Bet();

                const room: IGameRoom = this.getRoom(cs.roomid);

                if (!room) {
                    sc.errorcode = EnumErrorCode.NotFoundGameRoom;
                    user.send(sc);
                    return;
                }
                let totalCost: number = 0;
                _.each(cs.info.bets, (b) => {
                    totalCost += b.coin;
                });


                if (totalCost > user.data.gameData.coins) {
                    sc.errorcode = EnumErrorCode.CoinNotEnough;
                    user.send(sc);
                    return;
                }
                const ret: EnumErrorCode = await room.vote(user, cs);
                sc.errorcode = ret;

                break;
            }
            case EnumProtocolType.CS_GetRoomInfo: {

                const cs: CS_GetRoomInfo = <CS_GetRoomInfo>req;
                const sc: SC_GetRoomInfo = new SC_GetRoomInfo();
                const room: GameRoomEntity = this.getRoom(cs.roomid);
                if (!room) {
                    sc.errorcode = EnumErrorCode.NotFoundGameRoom;
                    user.send(sc);
                    return;
                }
                user.send(sc);
                break;
            }
            case EnumProtocolType.CS_GetRoomList: {
                const sc: SC_GetRoomList = new SC_GetRoomList();

                _.each(this._rooms, (room) => {
                    sc.list.push(room.data);
                });
                user.send(sc);
                break;

            }

            case EnumProtocolType.CS_EnterGameRoom: {
                const cs: CS_EnterGameRoom = <CS_EnterGameRoom>req;
                const room: GameRoomEntity = RoomManager.inst.getRoom(cs.roomid);
                const sc: SC_EnterGameRoom = new SC_EnterGameRoom();
                if (!room) {
                    sc.errorcode = EnumErrorCode.RoomtNotFound;
                }
                else if (user.data.gameData.roomId == cs.roomid) {
                    sc.errorcode = EnumErrorCode.HadInRoom;
                }
                else {
                    if (!_.find(room.data.onlineUsers, cs.roomid)) {
                        room.data.onlineUsers.push(user.data.uid);
                    }
                    user.data.gameData.roomId = cs.roomid;


                    Log.debug(`用户${user.data.uid}进入了房间${cs.roomid}`);
                }

                sc.room = room.data;

                user.send(sc);
                break;
            }
            case EnumProtocolType.CS_GetBetHistory: {
                const cacheComp: CacheComponent = <CacheComponent>LogicServer.entity.getComponent(CacheComponent);
                const orders: { [key: string]: GameBetOrderInfo } = await cacheComp.get(EnumCacheGroup.USER_ORDER, user.data.uid);

                const sc: SC_GetBetHistory = new SC_GetBetHistory();


                if (orders) {
                    _.each(orders, order => {
                        sc.list.push(order);
                    });
                }
                user.send(sc);

                break;
            }

            case EnumProtocolType.CS_ExitGameRoom: {
                if (user.data.gameData.roomId != "") {
                    const room: IGameRoom = this.getRoom(user.data.gameData.roomId);
                    _.remove(room.data.onlineUsers, user.data.gameData.roomId);
                    user.data.gameData.roomId = "";

                }
                const sc: SC_ExitGameRoom = new SC_ExitGameRoom();
                user.send(sc);

                break;
            }
            default: {
                break;
            }

        }

    }

    public init(): void {

        const cacheComp: CacheComponent = <CacheComponent>LogicServer.entity.getComponent(CacheComponent);

        _.each(RoomConfig, async (config) => {
            let roominfo: GameRoomInfo = await cacheComp.get(EnumCacheGroup.ROOM_INFO, config.id.toString());
            if (!roominfo) {

                roominfo = new GameRoomInfo();
                roominfo.configId = config.id;
                roominfo.startTime = Tools.getServerTime();
                roominfo.createTime = Tools.getServerTime();
                roominfo.expireTime = roominfo.startTime + config.intervalTime;
                roominfo.prizePool = config.basePrize;
                await cacheComp.set(EnumCacheGroup.ROOM_INFO, config.id.toString(), roominfo);





            }

            let room: IGameRoom;
            switch (config.type) {
                case EnumRoomType.FAST_SINGLE: {
                    room = new GameRoomFastSingle();
                    room.setData(roominfo);

                    break;
                }
                case EnumRoomType.Normal: {

                    room = new GameRoomFastSingle();
                    room.setData(roominfo);
                    break;
                }
                default: {
                    Log.error("not found roomt type");
                    break;
                }
            }
            this._rooms.push(room);


        });




    }


    public update(servertime: number): void {

        _.each(this._rooms, room => {
            room.update(servertime);
        });
    }

}
